#include "configParse.h"

const char *configOptionName[] = {
	"SERVER_IP",
	"SERVER_PORT",
	"WORKER_THREAD_NUM",
	"DEBUG_LEVEL",
	"KEEP_ALIVE_TIME",
	"MAX_CONNECT_NUM",
	"LOG_OUT_PUT_MODE",
	"LOG_OUT_PUT_PATH",
	"LOG_BUF_LEN",
	"LOG_BUF_BLOCK_NUM",
	"DOCUMENT_ROOT",
	"INDEX_HTML_PATH",
	"ENABLE_DIRECTORY_LISTING", 
	"HTTP_GZIP_SWITCH", 
	NULL
};

/*
 *@brief:
 *
 */
int parseConfigOption(struct serverConfigOpt **opt, char *keyName, char *value){
	int index = 0;
	int port = -1;
	int keepAliveTime = 0;
	size_t bufLen = 0;
	size_t bufBlockNum = 0;
	int outputMode = -1;
	int debugLevel = -1;
	int threadNum = -1;
    char gzipswitch[20] = {'\0'};
	size_t maxconnSize = 0;
	int iRet = RET_ERROR;
	for(; configOptionName[index]!=NULL; index++){
		iRet = memcmp(keyName, configOptionName[index], strlen(configOptionName[index]));
		if( iRet == RET_OK){
			switch(index){
				case SERVER_IP_OPT:	
					iRet = isAvaliableIpAddress(value);
					if ( iRet == RET_OK){
						(*opt)->serverIp = strdup(value);
					}else{
						goto failed;
					}
					break;
				case SERVER_PORT_OPT:
					port = atoi(value);
					iRet = isNotZero(port);
					if(iRet == RET_OK){
						(*opt)->listenPort = port;
					}else{
						goto failed;
					}
					break;
				case WORKER_THREAD_NUM_OPT:
					threadNum = atoi(value);
					iRet = isBigThanZero(threadNum, 100);
					if(iRet == RET_OK){
						(*opt)->threadNum = threadNum;
					}else{
						goto failed;
					}
					break;
				case DEBUG_LEVEL_OPT:
					//参数检查
					debugLevel = atoi(value);
					iRet = isNotZero(debugLevel);
					if(iRet == RET_OK){
						(*opt)->debugLevel = atoi(value);
					}else{
						goto failed;
					}
					break;
				case KEEP_ALIVE_OPT:
					keepAliveTime = atoi(value);
					iRet = isNotZero(keepAliveTime);
					if(iRet == RET_OK){
						//开启了超时机制;
						(*opt)->keepAliveTime = keepAliveTime;
						(*opt)->keepAlive = true;
					}else{
						//未开启超时机制;
						(*opt)->keepAliveTime = 0;
						(*opt)->keepAlive = false;
					}
					break;
				case MAX_CONNECT_NUM_OPT:
					maxconnSize = atoi(value);
					iRet = isNotZero(maxconnSize);
					if(iRet == RET_OK){
						(*opt)->maxconnSize = maxconnSize;
						iRet = setMaxFdSize(maxconnSize);
					}else{
						goto failed;
					}
					break;
				case LOG_OUT_PUT_MODE_OPT:
					//参数检查
					outputMode = atoi(value);
					iRet = isBigThanZero(outputMode, 1);
					if ( iRet == RET_OK){
						(*opt)->OutPutMode = outputMode;
					}else{
						goto failed;
					}
					break;
				case LOG_OUT_PUT_PATH_OPT:
					//参数检查;
					iRet = isExistFile(value);
					if( iRet == RET_OK){
						(*opt)->outPutLogPath = strdup(value);
					}else{
						goto failed;
					}
					break;
				case LOG_BUF_LEN_OPT:
					//参数检查;
					bufLen = (size_t)atoi(value);
					iRet = isBigThanZero(bufLen, 2048);
					if( iRet == RET_OK){
						(*opt)->buffLogLen = bufLen;
					}else{
						goto failed;
					}
					break;
				case LOG_BUF_BLOCK_NUM_OPT:
					//参数检查; 
					bufBlockNum = (size_t)atoi(value);
					iRet = isBigThanZero(bufLen, 2048);
					if (iRet == RET_OK){
						(*opt)->buffBlockNum = bufBlockNum;
					}else{
						goto failed;
					}
					break;
				case DOCUMENT_ROOT_OPT:
					iRet = isExistFile(value);
					if( iRet == RET_OK){
						(*opt)->rootDirPath = strdup(value); 
					}else{
						goto failed;
					}
					break;
				case INDEX_HTML_PATH_OPT:
					iRet = isExistFile(value);
					if( iRet == RET_OK){
						(*opt)->indexHtmlPath = strdup(value);
					}else{
						goto failed;
					}
					break;
				case ENABLE_DIRECTORY_LISTING_OPT:
					(*opt)->enable_directory_listing = strdup(value);
					break;
				case HTTP_GZIP_SWITCH_OPT:
                    sprintf(gzipswitch, "%s", value);
					if(strcmp(gzipswitch, "on") == 0){
						(*opt)->gzipOnFlag = true;
					}else if(strcmp(gzipswitch, "off") == 0){
						(*opt)->gzipOnFlag = false;
					}else{
						goto failed;
					}
					DEBUG_TRACE(("[debug]gzip On Switch:%d\n", (*opt)->gzipOnFlag));
					break;
				default:
					fprintf(stderr, "[error]unknown optionName:[%s] find in file:[%s] func:[%s] line:[%d]\n", keyName, __FILE__,__func__,__LINE__);
					goto failed;
			}
		}else{
			continue;	
		}
	}
	return RET_OK;
failed:
	return RET_ERROR;
}

/*
 *@brief:
 */
void optKeyFree(char **optKey, gsize ConfigOptNum){
	gsize optindex = 0;
	for(; optindex < ConfigOptNum; optindex++){
		if(optKey[optindex]){
			free(optKey[optindex]);
			optKey[optindex] = NULL;
		}
	}
	if(optKey){
		free(optKey);
		optKey = NULL;
	}
}

/*
 *@brief:
 */
void groupsKeyFree(char **groups, gsize ConfigDomainNum){
	gsize ConfigOptNum = 0;
	for( ; ConfigOptNum < ConfigDomainNum; ConfigOptNum++){
		if(groups[ConfigOptNum]){
			free(groups[ConfigOptNum]);
			groups[ConfigOptNum] = NULL;
		}
	}
	if(groups){
		free(groups);
		groups = NULL;
	}
}

/*
 *@brief:
 *
 */
int initServerConfigOpt(struct webServerCtx *serverctx,  const char * configPath){
	char *value = NULL;
	gsize domainindex = 0;
	char **optKey = NULL;
	char **groups = NULL;
	GError *error = NULL;
	gsize  ConfigDomainNum = 0; 
	int iRet = RET_ERROR;
	iRet = isExistFile(configPath);
	if (iRet == RET_ERROR){
		fprintf(stderr, "[error]%s in file:%s func:%s line:%d\n",strerror(errno), __FILE__, __func__, __LINE__);
		return iRet;
	}
	serverctx->opt = (struct serverConfigOpt *)malloc(sizeof(struct serverConfigOpt));
	if(!(serverctx->opt)){
		return RET_ERROR;
	}
	memset(serverctx->opt, 0, sizeof(struct serverConfigOpt));
	serverctx->opt->config = g_key_file_new();
	if (!(serverctx->opt->config)){
		fprintf(stderr, "[error]%s in file:[%s]  func:[%s] line:[%d]\n", strerror(errno), __FILE__,__func__,__LINE__);
		return RET_ERROR;
	}
	serverctx->opt->maxconnSize = 1024;
	g_key_file_load_from_file(serverctx->opt->config, configPath, G_KEY_FILE_NONE, &error);
	groups = g_key_file_get_groups(serverctx->opt->config, &ConfigDomainNum);
	gsize ConfigOptNum = 0;
	for ( domainindex = 0; domainindex < ConfigDomainNum; domainindex++){
		optKey = g_key_file_get_keys(serverctx->opt->config, groups[domainindex], &ConfigOptNum, &error);
		gsize optIndex;
		for( optIndex = 0; optIndex < ConfigOptNum; optIndex++){
		   value = g_key_file_get_string(serverctx->opt->config, groups[domainindex], optKey[optIndex], &error);
		   DEBUG_TRACE(("[debug]optionName:%-30s    :%-10s\n", optKey[optIndex], value)); 
		   iRet = parseConfigOption(&(serverctx->opt), optKey[optIndex], value);
		   if (iRet == RET_ERROR){
			   fprintf(stderr, "[error]:parse opion:[%s] occur error in file:[%s] func:[%s] line:[%d]\n", optKey[optIndex], __FILE__,__func__,__LINE__);
			   if(value){
				   free(value);
				   value = NULL;
			   }
               optKeyFree(optKey, ConfigOptNum);
			   goto failed;
		   }
		   if(value){
			   free(value);
			   value = NULL;
		   }
	    }
		//optKeyFree;
		optKeyFree(optKey, ConfigOptNum);
	}
	groupsKeyFree(groups, ConfigDomainNum);
	//groupsKeyFree; 
	return RET_OK;
failed:
	groupsKeyFree(groups, ConfigDomainNum);
	return RET_ERROR;
}

void ServerConfigDeinit(struct serverConfigOpt *opt){
	if(!opt){
		fprintf(stderr, "[error]%s in file:[%s] func:[%s] line:[%d]\n", strerror(errno), __FILE__, __func__, __LINE__);
		return;
	}
	if(opt->config){
		g_key_file_free(opt->config);
        opt->config = NULL;
    }
	if(opt->serverIp){
		free(opt->serverIp);
		opt->serverIp = NULL;
	}
	if(opt->outPutLogPath){
		free(opt->outPutLogPath);
		opt->outPutLogPath = NULL;
	}
	if(opt->rootDirPath){
		free(opt->rootDirPath);
		opt->rootDirPath = NULL;
	}
	if(opt->indexHtmlPath){
		free(opt->indexHtmlPath);
		opt->rootDirPath = NULL;
	}
	if(opt->enable_directory_listing){
		free(opt->enable_directory_listing);
		opt->enable_directory_listing = NULL;
	}
    if(opt){
        free(opt);
        opt = NULL;
    }
	return;
}
